<template>
  <div :id="tableId" style="position: relative;display: table;width: 100%;height: 100%" @contextmenu.prevent.stop>
    <right-key-menu :ref="tableId+'menu'" :menu-list="menuList" />
    <div
      class="dynamic-table2-wapper"
      :style="{height: `${options.heightAdaptive ? '100%' :'auto'}`}"
    >
      <table
        v-if="reflush"
        :key="renderTHeadData.length+renderTBodyData.length"
        class="dynamic-table2"
        style="height: 100%;"
        :style="{
          borderTop: tableBorderTobBottom(),
          borderBottom: tableBorderTobBottom(),
          borderLeft: tableBorderLeftRight(),
          borderRight: tableBorderLeftRight()
        }"
        :class="{'isPreview':!isEdit,'noPreview':isEdit}"
        @mousedown="mouseDown"
        @mousemove="mouseMove"
        @mouseup="mouseUp"
        @keyup.tab="getInFocus"
      >
        <colgroup v-for="(item,index) in cols" :key="index" :style="{width: item.tableCellWidth?item.tableCellWidth+'%':(1/cols.length*100) +'%'}" />
        <!-- 表格主体 		 -->
        <tr v-for="(tr,row) in renderTBodyData" :key="'tdrow'+row">
          <template v-for="(td,col) in tr">
            <!-- td被删除不显示   传入是否显示标记为true时,根据单元格属性判断是否显示  正式模式下单元格部分默认不显示,表头部分默认显示-->
            <td
              v-if="!td.isRemove && (isShow ? td.isShow : true) && (!td.tag || (td.tag ==='td' /**&& showTableTd**/) || td.tag === 'th')"
              id="TdId"
              :key="`td-${row}-${col}`"
              :rowspan="td.rowspan || 1"
              :colspan="td.colspan || 1"
              :align="alignDict[td.align]"
              :valign="valignDict[td.valign]"
              style="color: #8691A0;word-break: break-all"
              :style="tdStyle(td, renderTBodyData, row, col)"
              :data-select-flag="`td-${row}-${col}-${td.rowspan}-${td.colspan}`"
              :class="{'cell':true,'brder-bottom-none':row+td.rowspan>=renderTBodyData.length,
                       'isedit':td.isEditCell&&td.cellType==='text'&& !selectCells.includes(`td-${row}-${col}-${td.rowspan}-${td.colspan}`),
                       select:selectCells.includes(`td-${row}-${col}-${td.rowspan}-${td.colspan}`)
              }"
              @drop.stop="handleTargetDrop"
              @dragover="handleTargetDragOver"
              @click="tablePropertiesInputValue(td,row,col)"
            >
              <!-- 一种是回显 -->
              <span v-show="(isEdit && td.label) || (!isEdit && showTableTd)" class="noExl" v-html="getVal('td', td, row,col)" />
              <!-- 一种是可输入 -->
              <evol-input
                v-if="!td.label && isEdit"
                :ref="`td-${row}-${col}-${td.rowspan}-${td.colspan}val`"
                v-model="td.val"
                :style="{textDecoration:td.underline ? 'underline' : 'none'}"
                :is-edit="isEdit"
                @keydown.native="inputKeyDown"
              />
            </td>
          </template>
        </tr>
      </table>
      <div v-if="isShowNoData" class="d-flex j-center" :style="{borderTop: `1px solid ${options.rowBorderColor ? options.rowBorderColor : generalTableConstant.TABLE_OPTIONS.rowBorderColor}`,}">
        <v-noData />
      </div>
    </div>
  </div>
</template>

<script>
import { flatten } from '@/utils/array-utils'
import * as generalTableConstant from '@/components/GeneralTable/generalTableConstant'
// 获取单元格
function getCell(dom) {
  if (dom.tagName === 'BODY') return null
  return (dom.tagName === 'TH' || dom.tagName === 'TD') ? dom : getCell(dom.parentNode)
}
// 数组求和
function sum(arr) {
// eslint-disable-next-line no-eval
  return eval(arr.join('+'))
}
// 右键菜单组件
import RightKeyMenu from '../right-key-menu.vue'
import EvolInput from '../evol-input.vue'
let uid = 0
/**
 * 动态表格
 */
export default {
  components: {
    RightKeyMenu,
    EvolInput
  },
  props: {
    // 是否为编辑
    isEdit: {
      type: Boolean,
      default: true
    },
    tableModel: {
      type: Number,
      default: 0
    },
    // 表格配置
    options: {
      type: Object,
      default: () => {}
    },
    // 单元格配置
    cellOptions: {
      type: Object,
      default: () => {}
    },
    // 每一个单元格中的isShow是否生效
    isShow: {
      type: Boolean,
      default: false
    },
    // 当前拖拽的数据
    dataTransferData: {
      type: Object,
      default: () => {}
    },
    /**
     * 映射函数，两个单元格之间的映射关系
     */
    mappingFunction: {
      type: Function,
      default(item, singleDataMap, renderTBodyData) {
        return item.val
      }
    },
    /**
     * 保存映射关系函数
     */
    saveMappingFunction: {
      type: Function,
      default(selectCells, renderTBodyData) {
        return ''
      }
    }
  },
  data() {
    return {
      defaultTableOptions: JSON.parse(JSON.stringify(generalTableConstant.TABLE_OPTIONS)),
      defaultCellOptions: JSON.parse(JSON.stringify(generalTableConstant.CELL_OPTIONS)),
      tableProperty: {}, // 表格整体的属性设置
      tableExtendProperty: {}, // 表格扩展属性值
      dataComplete: false, // 数据加载完成标志
      tableComplete: false, // 表格加载完成标志
      sizeDict: {
        '小': '14px',
        '中': '18px',
        '大': '22px'
      },
      alignDict: {
        '左': 'left',
        '中': 'center',
        '右': 'right'
      },
      valignDict: {
        '上': 'top',
        '中': 'middle',
        '下': 'bottom'
      },
      // tableJson: {}, // 表格配置缓存对象
      reflush: true, // 强制刷新表格
      // 对齐方式
      result: 0,
      cellHeight: 30, // 一个单元格的基础高度
      cellWidth: 25,
      tableId: 'evol-' + +new Date(),
      renderTHeadData: [],
      renderTBodyData: [],
      selectCells: [], // 被选中的单元格 标志数组
      cells: null,
      mouseEventDom: null, // 鼠标当前所在单元格
      timer: null, // 选择定时器 单鼠标按下并且移动时 开始框选
      mouseDownCell: null, // 鼠标按下时的节点
      rightDownCell: null, // 鼠标右键按下的节点
      menuList: [], // 右键菜单列表
      allowMerging: false, // 是否允许合并单元格
      currDataType: 'static',
      defaultVal: [],
      isShowNoData: false
    }
  },
  computed: {
    // 单元格是否显示额外规则
    showTableTd() {
      // 当前在预览页面
      if (!this.isEdit) {
        // 数据加载完成则显示 否则不显示
        return this.dataComplete
      } else {
        // 否则默认为显示
        return true
      }
    },
    currBandApi() {
      return this.options.bandApi
    },
    isShowSelect() {
      return this.options.dataType === 'dynamic'
    },
    cols() {
      if (this.renderTHeadData.length === 0 && this.renderTBodyData.length === 0) {
        return 0
      } else if (this.renderTHeadData.length === 0) {
        return this.renderTBodyData[0]
      }
      return this.renderTBodyData[0]
    },
    // 表格json对象
    tableJsonObj() {
      // 表格加载完成之后返回数据
      return this.tableComplete ? {
        data: {
          thData: this.renderTHeadData,
          tdData: this.renderTBodyData
        },
        options: this.tableProperty,
        extendOptions: this.tableExtendProperty
      } : {}
    }
  },
  watch: {
    isShowSelect() { // 动静态数据发生改变 清除th显示信息
      this.renderTHeadData.forEach(item => {
        item.forEach(cell => {
          cell.val = ''
        })
      })
    },
    options: {
      handler(val) {
        if (this.options.changeKey && this.options.changeKey.length) {
          this.setTableStyle()
        }
      },
      immediate: true, // 刷新加载 立马触发一次handler
      deep: true // 可以深度检测到  对象的属性值的变化
    },
    // 监听表格数据发生变化
    tableJsonObj: {
      handler(val, oldVal) {
        // 非编辑模式 返回
        if (!this.isEdit) return
        // 触发表格json变化方法
        this.$emit('tableJsonChange', {
          oldTableJsonObj: oldVal,
          newTableJsonObj: val
        })
      },
      deep: true
    },
    tableModel(val) {
      this.renderTBodyData.forEach(row => {
        row.forEach((currCell, index) => {
          const types = ['text', 'radio', 'checkbox']
          currCell.label = ''
          currCell.otherVal = ''
          currCell.val = ''
          currCell.otherSelect = ''
          currCell.cellType = types[val]
          currCell.otherSelect = false
        })
      })
    },
    isEdit(val) {
      if (!val) {
        // this.$refs[this.tableId + 'setTypeTip'].close()
        this.selectCells = []
      }
    },
    cellOptions: {
      handler(val) {
        if (this.cellOptions.changeKey && this.cellOptions.changeKey.length) {
          this.setSelectCellStyle()
        }
      },
      deep: true // 可以深度检测到  对象的属性值的变化
    }
  },
  mounted() {
    // 点击空白处，取消选择
    document.addEventListener('click', this.endSelect, false)
  },
  methods: {
    /**
     * @param {Object} td
     * @param {Object} renderTBodyData
     * @param {Object} row
     * @param {Object} col
     * 表格td的样式
     */
    tdStyle(td, renderTBodyData, row, col) {
      // 当前的模式
      const configMode = this.tableProperty.configMode
      // 如果是内置项目，则使用内置项目的配置
      // const configModeBgColor = configMode === 'internal' ? this.tableProperty.cellFill : ''
      const configModeColor = configMode === 'internal' ? this.tableProperty.color : ''
      const configModeRowBorderColor = configMode === 'internal' ? this.tableProperty.rowBorderColor : ''
      const configModeColBorderColor = configMode === 'internal' ? this.tableProperty.colBorderColor : ''
      const styleObj = {
        height: this.calculationHeight(td, renderTBodyData, row, col),
        borderTop: row === 0 ? 'none' : this.borderTopFun(td, configModeRowBorderColor),
        borderBottom: this.borderBottomFun(td, configModeRowBorderColor),
        borderLeft: this.borderLeftFun(td, configModeColBorderColor),
        borderRight: this.borderRightFun(td, configModeColBorderColor),
        /* 如果是内置项目，则使用内置项目，否则：设置的默认色为rgba(254, 254, 254, 1)，所以如果不是默认色则认为有单独的样式*/
        backgroundColor: td.cellFill !== 'rgba(254, 254, 254, 1)' ? td.cellFill : this.tableProperty.cellFill,
        /* 为了兼容,先判断单元格自身的填充色是否是默认色,是默认色则代表没有设置单独的样式*/
        color: this.tdTextColor(td, configModeColor),
        fontSize: this.sizeDict[td.size],
        fontStyle: td.isItalic ? 'italic' : 'normal',
        textDecoration: td.underline ? 'underline' : 'none',
        fontWeight: td.isWeight ? 'bold' : 'normal'
      }
      return styleObj
    },
    /**
     * @param {Object} td
     * 表格td的文本颜色
     */
    tdTextColor(td, configModeColor) {
      // td.color === defaultColor ? this.tableProperty.color : (td.isColorChange ? td.color : (this.isEdit ? (td.tag === 'th' || !td.tag ? '#000000' : 'rgba(20, 0, 0, 1)') : '#000000'))
      // 单元格文字的默认色
      const defaultColor = generalTableConstant.DEFAULT_CELL.color
      // 当前单元格的颜色是否是默认色（没有设置）
      const tdColor = !!(td.color === defaultColor)
      // 如果当前属于拖拽的数据 并且单元格是默认色 并且是编辑模式，并且全局文本颜色为默认色（没有设置文本颜色）则为true
      const isDragFlag = !!(tdColor && td.dataSetCode && this.isEdit && this.options.color === defaultColor)
      // isDragFlag为true则显示灰色，否则就按照正常的输入字段颜色显示:如果是内置则显示内置
      return isDragFlag ? 'rgba(134, 145, 160,1)' : (tdColor ? (configModeColor || this.options.color) : (td.isColorChange ? td.color : (this.isEdit ? (td.tag === 'th' || !td.tag ? '#000000' : defaultColor) : '#000000')))
      // return isDragFlag ? 'rgba(134, 145, 160,1)' : (tdColor ? this.tableProperty.color : (td.isColorChange ? td.color : (this.isEdit ? (td.tag === 'th' || !td.tag ? '#000000' : defaultColor) : '#000000')))
    },
    /**
     * 计算表格属性高度的改变值
     * @param {Object} td
     */
    calculationHeight(td, renderTBodyData, rowIndex, colIndex) {
      const height = td.tableCellHeight ? parseInt(td.tableCellHeight) * td.rowspan + 'px' : '30px'
      return height
    },
    /**
     * 选择某个单元格后再回显表格属性的宽度和高度
     */
    tablePropertiesInputValue(val, rowIndex, colIndex) {
      if (!this.isEdit) return
      const height = isNaN(parseInt(val.tableCellHeight)) ? parseInt(this.cellHeight) : parseInt(val.tableCellHeight)
      const width = this.cols[colIndex].tableCellWidth ? parseInt(this.cols[colIndex].tableCellWidth) : parseInt((1 / this.cols.length * 100) + '%')
      this.$parent.sendEasyTable([width, height, val])
    },

    /**
     * 表格的上下边框线
     */
    tableBorderTobBottom() {
      const configMode = this.tableProperty.configMode
      const borderSize = this.options.borderSize || this.defaultTableOptions.borderSize
      // 如果是内置配置，就取内置配置，否则：如果有手动调整边框线尺寸的话就是手动调整的，否则就用默认的
      const borderColor = configMode === 'internal' ? this.tableProperty.rowBorderColor : (this.options.rowBorderColor || this.defaultTableOptions.rowBorderColor)
      return borderSize + 'px solid ' + borderColor
    },
    /**
     * 表格的左右边框线
     */
    tableBorderLeftRight() {
      const configMode = this.tableProperty.configMode
      const borderSize = this.options.borderSize || this.defaultTableOptions.borderSize
      // 如果是内置配置，就取内置配置，否则：如果有手动调整边框线尺寸的话就是手动调整的，否则就用默认的
      const borderColor = configMode === 'internal' ? this.tableProperty.colBorderColor : (this.options.colBorderColor || this.defaultTableOptions.colBorderColor)
      return borderSize + 'px solid ' + borderColor
    },
    /**
     * 单元格的上边框线
     */
    borderTopFun(td, configModeRowBorderColor) {
      // selectFlag: "td-0-0-1-1"

      const defBorderSize = this.defaultTableOptions.borderSize
      const borderSize = this.options.borderSize ? this.options.borderSize : defBorderSize

      const defRowBorderColor = this.defaultTableOptions.rowBorderColor
      // 优先级问题，如果有单独设置单元格的边框线颜色，则优先取单元格边框线颜色，否则：如果有内置就取内置没有的话则取整个表格的
      const rowBorderColor = td.topBorderColor ? td.topBorderColor : (configModeRowBorderColor || (this.options.rowBorderColor ? this.options.rowBorderColor : defRowBorderColor))
      return borderSize + 'px solid ' + rowBorderColor
    },
    /**
     * 单元格的下边框线
     */
    borderBottomFun(td, configModeRowBorderColor) {
      const defBorderSize = this.defaultTableOptions.borderSize
      const borderSize = this.options.borderSize ? this.options.borderSize : defBorderSize

      const defRowBorderColor = this.defaultTableOptions.rowBorderColor
      // 优先级问题，如果有单独设置单元格的边框线颜色，则优先取单元格边框线颜色，否则：如果有内置就取内置没有的话则取整个表格的
      const rowBorderColor = td.bottomBorderColor ? td.bottomBorderColor : (configModeRowBorderColor || (this.options.rowBorderColor ? this.options.rowBorderColor : defRowBorderColor))
      return borderSize + 'px solid ' + rowBorderColor
    },
    /**
     * 单元格的左边框线
     */
    borderLeftFun(td, configModeColBorderColor) {
      const defBorderSize = this.defaultTableOptions.borderSize
      const borderSize = this.options.borderSize ? this.options.borderSize : defBorderSize

      const defColBorderColor = this.defaultTableOptions.colBorderColor
      // 优先级问题，如果有单独设置单元格的边框线颜色，则优先取单元格边框线颜色，否则：如果有内置就取内置没有的话则取整个表格的
      const colBorderColor = td.leftBorderColor ? td.leftBorderColor : (configModeColBorderColor || (this.options.colBorderColor ? this.options.colBorderColor : defColBorderColor))
      return borderSize + 'px solid ' + colBorderColor
    },
    /**
     * 单元格的右边框线
     */
    borderRightFun(td, configModeColBorderColor) {
      const defBorderSize = this.defaultTableOptions.borderSize
      const borderSize = this.options.borderSize ? this.options.borderSize : defBorderSize

      const defColBorderColor = this.defaultTableOptions.colBorderColor
      // 优先级问题，如果有单独设置单元格的边框线颜色，则优先取单元格边框线颜色，否则：如果有内置就取内置没有的话则取整个表格的
      const colBorderColor = td.rightBorderColor ? td.rightBorderColor : (configModeColBorderColor || (this.options.colBorderColor ? this.options.colBorderColor : defColBorderColor))
      return borderSize + 'px solid ' + colBorderColor
    },
    /**
		 * 拖拽移入
		 * @param {Object} e
		 */
    handleTargetDragOver(e) {
      const cell = getCell(e.toElement || e.explicitOriginalTarget)
      // 当前拖拽至的单元格的样式配置
      const cellInfoParse = this.cellInfoParse(cell.dataset.selectFlag)
      // 当前拖拽至的单元格的值
      const cellVal = this.renderTBodyData[cellInfoParse.rowIndex][cellInfoParse.colIndex].val
      /**
			 * 横向合计和纵向合计不能同时出现在同一行或同一列
			 * 思路:
			 *  1.判断是否为横纵向合计
			 * 		行没有重复&&列没有重复&&当前单元格无内容 -> 可放置
			 *  2.不是横纵合计
			 *   2.2当前单元格无内容 -> 可放置
			 */
      // 取另一个
      const getRowCellOther = () => {
        return this.dataTransferData.key === 'transverseTotal' ? 'verticalTotal' : 'transverseTotal'
      }
      if (['transverseTotal', 'verticalTotal'].includes(this.dataTransferData.key)) {
        // 行
        const rowData = this.renderTBodyData[cellInfoParse.rowIndex].map(item => item.key)
        // 列
        const colData = this.renderTBodyData.map(item => item[cellInfoParse.colIndex].key)
        if (!rowData.includes(getRowCellOther()) &&
						!colData.includes(getRowCellOther()) &&
						!cellVal) {
          e.preventDefault() // 将光标变成可放置的
          return
        }
      }
      else {
        // 只能拖至无内容的单元格(将光标变成可放置的)
        if (!cellVal) e.preventDefault()
      }
    },
    /**
		 * 拖拽放置(可拖拽至任意位置)
		 * @param {Object} e
		 */
    handleTargetDrop(e) {
      // 传递过来的数据
      const content = JSON.parse(e.dataTransfer.getData('dragData'))
      let cellInfoParse = {}
      // 遍历所有的td找到拖到格子的详细信息
      // eslint-disable-next-line no-undef
      for (let i = 0; i < $('.dynamic-table2 td').length; i++) {
        // eslint-disable-next-line no-undef
        const thObject = $('.dynamic-table2 td').eq(i)
        var x = e.pageX
        var y = e.pageY
        var y1 = thObject.offset().top // div上面两个的点的y值
        var y2 = y1 + thObject.height()// div下面两个点的y值
        var x1 = thObject.offset().left // div左边两个的点的x值
        var x2 = x1 + thObject.width() // div右边两个点的x的值

        if (x < x1 || x > x2 || y < y1 || y > y2) {
          // alert('鼠标不在该DIV中');
        } else {
          // alert('鼠标在该DIV中');
          cellInfoParse = this.cellInfoParse(thObject.attr('data-select-flag'))
          break
        }
      }
      const row = cellInfoParse['rowIndex']
      const col = cellInfoParse['colIndex']
      const setItem = (item, content, displayOrder) => {
        item[col] = { ...item[col], ...content }
        item[col]['displayOrder'] = displayOrder
      }

      // 特殊处理下横向合计和纵向合计
      if (['transverseTotal', 'verticalTotal'].includes(content.key)) {
        const item = this.renderTBodyData[row]
        setItem(item, content, 0)
        item[col]['tag'] = 'td'
        item[col]['supportTotal'] = content.supportTotal
        item[col]['val'] = content.label
      }
      else {
        // 数据填充为表头或者表体
        for (let i = row; i < this.renderTBodyData.length; i++) {
          const item = this.renderTBodyData[i]
          if (i === row) {
            if (content.resultType === 1) {
              // 单条数据填充为表体,跳出循环
              item[col]['tag'] = 'td'
              item[col]['supportTotal'] = content.supportTotal
              item[col].val = `值(${content.label})`

              setItem(item, content, i - row)
              break
            }
            else if (content.resultType === 2) {
              // 多条数据则填充为表头,继续向下遍历
              item[col].val = content.label
              setItem(item, content, null)
              item[col]['tag'] = 'th'
              item[col]['cellFill'] = '#F9FAFB'
              item[col]['isWeight'] = true
              continue
            }
          }
          // 如果有值了则做截断
          if (item[col].val) break
          // 填充表体
          setItem(item, content, i - row - 1) // -1的意思是 -> 顺序从0开始
          item[col]['tag'] = 'td'
          item[col]['supportTotal'] = content.supportTotal
          item[col].val = `值(${content.label})`
        }
      }
      // 选择单元格的下标
      // eslint-disable-next-line no-undef
      const selectFlag = $(e.target).attr('data-select-flag') || ''
      // 触发拖拽完成方法
      this.$emit('targetDropEnd', {
        renderTBodyData: this.renderTBodyData,
        content: content,
        selectFlag: selectFlag
      })
      this.$forceUpdate()
      e.preventDefault()
      // 通常不需要阻止冒泡，但是当出现容器嵌套时最好这么做
      // 它可以防止节点被添加到数组中两次
      e.stopPropagation()
    },
    /**
		 * 向外提供个获取当前拖拽的列数据方法
		 */
    getDataSetMappingRefList() {
      const result = []
      // 调用方法判断是否需要进行无限扩展 以及获取标准行信息
      const expansionObj = this.getExpansionFlag()
      // 获取标准行的数据
      if (expansionObj.isExpansion) {
        this.renderTBodyData[expansionObj.standardRowIndex].forEach(item => {
          if (item.dataSetCode && item.key)	result.push(item.dataSetCode + '&' + item.key)
        })
      }
      return [...new Set(result)]
    },
    /**
		 * 获取表格JSON方法
		 */
    getTableJSON() {
      return JSON.stringify({
        data: {
          // thData: this.renderTHeadData,
          tdData: this.renderTBodyData
        },
        options: this.options
      })
    },
    /**
		 * 设置选中单元格的样式
		 */
    setSelectCellStyle() {
      // 遍历选中单元格
      this.selectCells.forEach(item => {
        const cellInfoParse = this.cellInfoParse(item)
        // 根据变化的单元格key处理数据
        this.cellOptions.changeKey.forEach(item2 => {
          if (cellInfoParse.tag === 'td') {
            if (item2 === 'tableCellWidth') {
              this.renderTBodyData.forEach(item3 => {
                // 宽度要加索引，因为是一个列表
                this.$set(item3[cellInfoParse.colIndex], item2, this.cellOptions[item2])
              })
            }
            if (item2 === 'tableCellHeight') {
              this.renderTBodyData[cellInfoParse.rowIndex].forEach(item4 => {
                // 高度不用加索引
                this.$set(item4, item2, this.cellOptions[item2])
              })
            }
            this.renderTBodyData[cellInfoParse.rowIndex][cellInfoParse.colIndex][item2] = this.cellOptions[item2]
          } else {
            this.renderTHeadData[cellInfoParse.rowIndex][cellInfoParse.colIndex][item2] = this.cellOptions[item2]
          }
          this.$forceUpdate()
        })
      })
    },
    /**
		 * 设置表格整体的样式
		 */
    setTableStyle() {
      const changeKey = this.options.changeKey || []
      // 根据变化的key值同步修改表格属性值
      changeKey.forEach(item => {
        this.$set(this.tableProperty, item, this.options[item])
      })
      this.$forceUpdate()
    },
    /**
     * 修改表格扩展属性值
     * @param e {key:'',value:''}
     */
    changeTableExtendOptions(e) {
      // 修改值
      this.$set(this.tableExtendProperty, e.key, e.value)
    },
    // 判断是否需要向下无限扩展
    getExpansionFlag() {
      // 无限扩展标识
      let isOtherincludeTh = false // 其他行是否存在表头 false -> 不存在, true -> 存在
      let standardRowIndex = -1 	 // 标准行的索引
      let displayOrderMax = -1 		 // 最大的排序顺序
      this.renderTBodyData.forEach((item, index) => {
        let rowThList = item.map(item2 => item2.tag === 'th' ? 'th' : '')
        // 去重
        rowThList = [...new Set(rowThList)]
        if (rowThList.length === 1 && rowThList[0] === 'th') {
          // 1.先找到是否有标准行
          standardRowIndex = index
        }
        else {
          // 2.再判断其他行是否存在表头
          if (rowThList.includes('th')) isOtherincludeTh = true
        }
        // 求出最大的排序顺序
        if (!isOtherincludeTh && standardRowIndex !== -1) {
          displayOrderMax = Math.max.apply(null, item.map(item2 => item2.displayOrder || -1))
        }
      })

      return {
        isExpansion: !isOtherincludeTh && standardRowIndex !== -1, // 是否存在标准行
        standardRowIndex: standardRowIndex,												 // 标准行的索引
        displayOrderMax: displayOrderMax													 // 最大的排序顺序
      }
    },
    /**
     * 刷新表格配置
     * @param tableJson 表格json配置
     */
    refreshTable(tableJson) {
      // 转换json对象
      const tableJsonObj = JSON.parse(tableJson)
      // 初始化表头数据
      this.renderTHeadData = tableJsonObj.data.thData || []
      // 初始化表体数据
      this.renderTBodyData = tableJsonObj.data.tdData || []
      // 配置模式 内置或者自定义，有数据则是内置，没有则是自定义
      const configMode = tableJsonObj.options.configMode || 'custom'
      // 预览主题色
      const previewThemeColorCode = tableJsonObj.extendOptions ? tableJsonObj.extendOptions.previewThemeColorCode : ''
      // 如果当前为内置模式 且 存在预览主题色
      if (configMode === 'internal' && previewThemeColorCode) {
        // 则根据主题色设置样式
        this.internalStyle(previewThemeColorCode, tableJsonObj)
      }
      // 初始化表格属性数据
      Object.assign(this.tableProperty, tableJsonObj.options)
    },
    /**
		 * 表格回显
		 * @param {Object} tableJson
		 */
    echoTable(tableJson) {
      // 默认设置数据未加载
      this.dataComplete = false
      // 默认设置表格未加载
      this.tableComplete = false
      // 转换json对象
      const tableJsonObj = JSON.parse(tableJson)
      // 初始化表头数据
      this.renderTHeadData = tableJsonObj.data.thData || []
      // 初始化表体数据
      this.renderTBodyData = tableJsonObj.data.tdData || []
      // 配置模式 内置或者自定义，有数据则是内置，没有则是自定义
      const configMode = tableJsonObj.options.configMode || 'custom'
      // 预览主题色
      const previewThemeColorCode = tableJsonObj.extendOptions ? tableJsonObj.extendOptions.previewThemeColorCode : ''
      // 如果当前为内置模式 且 存在预览主题色
      if (configMode === 'internal' && previewThemeColorCode) {
        // 则根据主题色设置样式
        this.internalStyle(previewThemeColorCode, tableJsonObj)
      }
      setTimeout(() => {
        // 初始化表格属性数据
        Object.assign(this.tableProperty, tableJsonObj.options)
        // 初始化表格扩展属性数据
        Object.assign(this.tableExtendProperty, tableJsonObj.extendOptions)
        // 设置表格加载完成
        this.tableComplete = true
      }, 0)
      this.$forceUpdate()
    },
    /**
     * 更改为内置样式
     * tableJsonObj为引用关系
     */
    internalStyle(previewThemeColorCode, tableJsonObj) {
      const theme = generalTableConstant.autoConfigTable[previewThemeColorCode]
      // 取到当前枚举里面的所有属性的key
      const key = theme ? Object.keys(theme) : []
      // 遍历更改tableJsonObj.options里面所有的配置属性
      for (let i = 0; i < key.length; i++) {
        this.$set(tableJsonObj.options, key[i], theme[key[i]])
      }
    },
    /**
		 * 表格设置值
		 * @param {Object} multipleDataArray	多条数据集
		 * @param {Object} singleDataMap  		单条数据集
     * @param {Object} hiddenNoData       隐藏无数据展示
		 */
    tableSetValue(multipleDataArray, singleDataMap, hiddenNoData = false) {
      // 默认设置数据未加载
      this.dataComplete = false
      //! this.renderTBodyDataCopy.length ? this.renderTBodyDataCopy = JSON.parse(JSON.stringify(this.renderTBodyData)) : this.renderTBodyData = JSON.parse(JSON.stringify(this.renderTBodyDataCopy))
      // 如果传入false,则表示需要进行无数据效果的显示
      if (!hiddenNoData) {
        // 是否显示数据
        this.isShowNoData = !multipleDataArray.length && !Object.keys(singleDataMap).length
      }
      /**
       * 加法运算,解决精度问题
       * @param {Object} num1
       * @param {Object} num2
       */
      const numAdd = (num1, num2) => {
        var baseNum, baseNum1, baseNum2
        try {
          baseNum1 = num1.toString().split('.')[1].length
        } catch (e) {
          baseNum1 = 0
        }
        try {
          baseNum2 = num2.toString().split('.')[1].length
        } catch (e) {
          baseNum2 = 0
        }
        baseNum = Math.pow(10, Math.max(baseNum1, baseNum2))
        return (num1 * baseNum + num2 * baseNum) / baseNum
      }

      /**
       * 混合模式标准渲染逻辑(一个单元格一个单元格进行遍历)
       * @param expansionObj 扩展判断对象 用于获取是否存在标准行
       * @param skipTotal 合计项跳过标记 设置为true时不进行合计处理
       * reutrn 当前渲染到的多行数据的displayOrder值
       */
      const renderFunction = (expansionObj, skipTotal) => {
        // 当前渲染到的多行数据的displayOrder值
        let renderRowDisplayOrder = 0
        // 开启行合计数 且存在标准行时  动态为表头、表体的每行数据 末尾增加一项合计对象
        if (this.tableJsonObj.options.isRowTotal && expansionObj.isExpansion && !skipTotal) {
          // 表格处理
          if (this.renderTBodyData.length) {
            this.renderTBodyData.forEach((item, index) => {
              // 获取本行的最后一列数据对象
              const lastColData = JSON.parse(JSON.stringify(item[item.length - 1]))
              // 获取到最后一行的key不为transverseTotal 时 则添加数据 防止重复添加
              if (lastColData.key !== 'transverseTotal') {
                // 设置属性
                lastColData.align = '中' // 文字对齐方式默认居中
                lastColData.cellType = 'text' // 默认类型
                lastColData.colspan = 1 // 列合并默认为1
                lastColData.key = 'transverseTotal' // 设置key值
                lastColData.isRemove = false // 删除标记默认为false
                lastColData.rowspan = 1 // 行合并默认设置为1
                lastColData.size = '中' // 文字尺寸默认设置为大
                lastColData.label = '行合计' // 设置label值
                // 当前为标准行时 或者为td标记时
                if (index === expansionObj.standardRowIndex || lastColData.tag === 'td') {
                  lastColData.val = '行合计' // 文字显示
                } else {
                  lastColData.val = '' // 文字显示
                }
                // 将数据添加值数组中
                item.push(lastColData)
              }
            })
          }
        }
        // 开启列合计数 且存在标准行时 动态为表体的末尾增加一行数据
        if (this.tableJsonObj.options.isColTotal && expansionObj.isExpansion && !skipTotal) {
          // 表格处理
          if (this.renderTBodyData.length) {
            // 获取表体最后一行数据
            const lastTBodyDataArray = JSON.parse(JSON.stringify(this.renderTBodyData[this.renderTBodyData.length - 1]))
            // 判断不为空
            if (lastTBodyDataArray && lastTBodyDataArray.length) {
              // 获取到最后一行的key不为verticalTotal 时 则添加数据 防止重复添加
              if (lastTBodyDataArray[0].key !== 'verticalTotal') {
                // 遍历数据
                lastTBodyDataArray.forEach(item => {
                  // 设置属性
                  item.align = '中' // 文字对齐方式默认居中
                  item.valign = '中' // 文字垂直对齐方式默认居中
                  item.cellType = 'text' // 默认类型
                  item.colspan = 1 // 列合并默认为1
                  item.key = 'verticalTotal' // 设置key值
                  item.isRemove = false // 删除标记默认为false
                  item.rowspan = 1 // 行合并默认设置为1
                  item.size = '中' // 文字尺寸默认设置为大
                  item.label = '列合计' // 设置label值
                  item.val = '列合计' // 文字显示
                })
                // 添加到数组中
                this.renderTBodyData.push(lastTBodyDataArray)
              }
            }
          }
        }
        // 遍历渲染值
        this.renderTBodyData.forEach((item2, index) => {
          for (let i = 0; i < item2.length; i++) {
            const item = item2[i]
            /**
             * cellMapping,cellName
             * 渲染回显：判断是否自主输入并且有映射关系cellMapping
             * 传个函数，(item,dataTree,singleDataMap)
             * item.val = 外部传过来的函数.(item,dataTree,singleDataMap)
             */
            // 自主输入的并且存在映射关系cellMappping
            // eslint-disable-next-line no-prototype-builtins
            if (!item['tag'] && item.hasOwnProperty('cellMapping')) {
              if (!item.ergodicFlag) {
                item.ergodicFlag = true
                // 根据映射关系重置标题
                item.val = this.mappingFunction(item, singleDataMap, this.renderTBodyData)
              }
            }
            // 自主输入的+对空单元格+表头  不进行处理
            if (!item['tag'] || (!item['val'] && !item['dataSetCode']) || item['tag'] === 'th') continue
            // 设置单条数据
            if (item.resultType && item.resultType === 1) {
              // 获取编码
              const code = item['dataSetCode'] || ''
              // 获取key值
              const key = item['key']
              // 获取数据数组
              const dataArray = singleDataMap[code] || []
              // 获取匹配数据
              const matchingData = dataArray.length > 0 ? dataArray[0] : {}
              // 获取匹配值
              const val = Object.keys(matchingData).length ? matchingData[code + '&' + key] : ''
              // 赋值
              item['val'] = val || ''
            }
            // 设置多条数据
            if (item.resultType && item.resultType === 2 && item.displayOrder !== null) {
              // 判断是否需要作删减
              if (item.displayOrder >= multipleDataArray.length) {
                item['val'] = ''
                // continue
              } else {
                item['val'] = multipleDataArray[item.displayOrder][item['dataSetCode'] + '&' + item['key']] || ''
                renderRowDisplayOrder = item.displayOrder + 1
              }
            }
            // 设置横向合计
            if (item.key === 'transverseTotal') {
              // 当前行当前位置向前追溯
              let transverseTotal = 0
              for (let j = 0; j < item2.length; j++) {
                if (j === i) break
                // 计算合计值(支持合计的字段才进行统计)
                if (!isNaN(item2[j].val) && (!item2[j].tag || item2[j].tag !== 'th') &&
                item2[j].val !== '' && item2[j].supportTotal) transverseTotal = numAdd(parseFloat(item2[j].val), transverseTotal)
              }
              item['val'] = transverseTotal
            }
            // 设置纵向合计
            if (item.key === 'verticalTotal') {
              // 当前列当前位置向上追溯
              let verticalTotal = 0
              for (let j = 0; j < this.renderTBodyData.length; j++) {
                if (j === index) break
                const val = this.renderTBodyData[j][i].val
                // 计算合计值(支持合计的字段才进行统计)
                if (!isNaN(val) &&
                    (!this.renderTBodyData[j][i].tag ||
                    this.renderTBodyData[j][i].tag !== 'th') &&
                    val !== '' && this.renderTBodyData[j][i].supportTotal) {
                  verticalTotal = numAdd(parseFloat(val), verticalTotal)
                }
              }
              item['val'] = verticalTotal
            }
          }
        })
        // 当前不跳过合计计算时 (表示最终次渲染时,需要进行多余空白单元格处理)
        if (!skipTotal) {
          // 当前存在标准行时 才进行多余空白单元格删除操作
          if (expansionObj.isExpansion) {
            // 需要删除行的下标   由标准行索引 + 当前数据长度 + 1
            const startDelIndex = expansionObj.standardRowIndex + multipleDataArray.length + 1
            // 删除数据的长度
            let delLen = 0
            // 当前存在列合计时 且 至少存在一条数据时
            if (this.tableJsonObj.options.isColTotal && multipleDataArray.length > 0) {
              // 保留列合计行 (少删一行)
              delLen = this.renderTBodyData.length - startDelIndex - 1
            } else {
              delLen = this.renderTBodyData.length - startDelIndex
            }
            // 当需要删除的开始行下标 小于表格数据长度时  进行删除操作
            if (startDelIndex < this.renderTBodyData.length) {
              // 删除从当前下标+1行 之后的全部数据
              this.renderTBodyData.splice(startDelIndex, delLen)
            }
          }
        }
        return renderRowDisplayOrder
      }
      // 调用方法判断是否需要进行无限扩展 以及获取标准行信息
      const expansionObj = this.getExpansionFlag()
      // 分为 分页,不分页两种情况
      if (this.options.isPage) {
        // 直接渲染可见表格  不跳过合计行
        renderFunction(expansionObj, false)
      } else {
        /**
         * 不分页的渲染逻辑
         *   1.一行全为表头并且没有其他行存在表头,则支持无限扩展
         *   2.无限扩展时，标准行上下方根据表格配置进行渲染, 超出表格部分以标准行字段为依据进行渲染
		     */
        // 先渲染可见表格部分 跳过原本的合计行功能
        const renderRowDisplayOrder = renderFunction(expansionObj, true) // 当前渲染到的多行数据的displayOrder值
        // 判断需要进行无限扩展
        if (expansionObj.isExpansion && expansionObj.displayOrderMax + 1 < multipleDataArray.length) {
          // 1.算出截取向下扩展的数据
          const expansionData = multipleDataArray.slice(renderRowDisplayOrder, multipleDataArray.length)
          // 2.追加到renderTBodyData中(以标准行为基准)并设置值
          expansionData.forEach((item, index) => {
            const rowData = JSON.parse(JSON.stringify(this.renderTBodyData[expansionObj.standardRowIndex]))
            rowData.forEach(item => {
              item['cellFill'] = 'rgba(254, 254, 254, 1)'
              item['tag'] = 'td'
              item['isWeight'] = false
              item['isItalic'] = false
              item['underline'] = false
              item['displayOrder'] = renderRowDisplayOrder + index
              item['val'] = multipleDataArray[renderRowDisplayOrder + index][item['dataSetCode'] + '&' + item['key']] || item['val']
            })
            this.renderTBodyData.push(rowData)
          })
        }
        // 需要再次进行渲染  计算合计行数
        renderFunction(expansionObj, false)
      }
      this.$nextTick(() => {
        // 设置数据加载完成
        this.dataComplete = true
        // 触发数据加载完成方法
        this.$emit('dataComplete', {
          renderTHeadData: this.renderTHeadData,
          renderTBodyData: this.renderTBodyData
        })
      })
      // 返回渲染数据
      return JSON.parse(JSON.stringify(this.renderTBodyData))
    },
    /**
     * 清空选中的单元格
     */
    clearSelect() {
      this.selectCells = []
    },
    /**
     * 行列发生变化的时候触发
     */
    rowCelChange() {
      this.$nextTick(() => {
        const data = JSON.parse(JSON.stringify(this.options))
        data.bodyRowNum = this.renderTBodyData.length
        data.colNum = this.renderTBodyData[0].length
        this.$emit('changeTableSeting', {
          type: 'table',
          data: data
        })
      })
    },
    getUid() {
      return uid++
    },
    /**
		 * 设置表格
		 * @param {Object} headRowNum
		 * @param {Object} bodyRowNum
		 * @param {Object} colNum
		 */
    setTable(headRowNum, bodyRowNum, colNum) {
      this.reflush = false
      // 默认设置表格未加载
      this.tableComplete = false
      this.$nextTick(() => {
        this.reflush = true
        this.selectCells = []
        const cell = JSON.parse(JSON.stringify(generalTableConstant.DEFAULT_CELL))

        const types = ['text', 'radio', 'checkbox']
        cell.cellType = types[this.tableModel]

        cell.otherSelect = false
        this.renderTHeadData = new Array(headRowNum).fill('').map(item => {
          return new Array(colNum).fill('').map(item => {
            const itemCell = JSON.parse(JSON.stringify(generalTableConstant.DEFAULT_CELL))
            itemCell.isShow = itemCell.isWeight = true
            itemCell.isItalic = itemCell.underline = true
            itemCell.cellFill = this.tableOptions ? this.tableOptions.headerFill : '#F9FAFB'
            return itemCell
          })
        })
        this.renderTBodyData = new Array(bodyRowNum).fill('').map(item => {
          return new Array(colNum).fill('').map(item => {
            const itemCell = { ...cell }
            itemCell.isShow = true
            itemCell.cellFill = this.defaultTableOptions.cellFill// ? this.defaultTableOptions.cellFill : '#FFFFFF'
            return itemCell
          })
        })
        setTimeout(() => {
          // 设置表格加载完成
          this.tableComplete = true
        }, 0)
      })
    },
    getTableOffset() {
      const dom = document.getElementById(this.tableId).getElementsByClassName('dynamic-table2-wapper')[0]
      return {
        top: dom.offsetTop,
        left: dom.offsetLeft,
        width: dom.offsetWidth,
        height: dom.offsetHeight
      }
    },
    execInputFunc(info, selectFlag, func) {
      const data = info.tag === 'th' ? this.renderTHeadData : this.renderTBodyData
      // }
      try {
        if (data[info.rowIndex][info.colIndex].cellType === 'text' ||
            data[info.rowIndex][info.colIndex].cellType === 'result') {
          if (this.$refs[selectFlag + 'val'] && this.$refs[selectFlag + 'val'][0]) {
            this.$refs[selectFlag + 'val'][0]['input' + func]()
          }
        } else {
          if (this.$refs[selectFlag + 'label'] && this.$refs[selectFlag + 'label'][0]) {
            this.$refs[selectFlag + 'label'][0]['input' + func]()
          }
        }
      } catch (e) { console.log() }
    },
    /**
     * 选中规则
     * 鼠标动作有以下几种
     * 1.鼠标左键按下
     *    选中当前的单元格
     * 2.鼠标左键按下并且拖动
     * 		选中 起始点与与松开点的单元格
     * 3.鼠标右键按下
     *  弹出自定义菜单
     * -----------------------
     * 监听  mousedown mouseover  mouseup
     * ----------------
     */
    mouseDown(event) {
      if (!this.isEdit) {
        return
      }
      // 阻止事件冒泡
      event.stopPropagation()
      const cell = getCell(event.toElement || event.explicitOriginalTarget)
      if (event.button === 0 && cell.dataset && cell.dataset.selectFlag) { // 左键按下
      // 获取表格中 所有cell
        this.cells = Array.from(document.getElementById(this.tableId).getElementsByClassName('cell'))
        this.$refs[this.tableId + 'menu'].closeMenu()
        this.mouseDownCell = cell
        // 选中单元格
        this.selectCells = [cell.dataset.selectFlag]
        // 获取焦点
        const info = this.cellInfoParse(cell.dataset.selectFlag)
        setTimeout(() => {
          // input
          if (event.target.className !== 'input') {
            this.execInputFunc(info, cell.dataset.selectFlag, 'Focus')
          }
        }, 80)
      } else if (event.button === 2) {
        this.rightDownCell = cell
      }
      // 鼠标右键触发的mouseDown不进行往下处理
      if (event.button === 2)	return
      // 得到当前选中单元格的样式配置
      const cellInfoParse = this.cellInfoParse(cell.dataset.selectFlag)
      let item = {}
      if (cellInfoParse.tag === 'td') {
        item = this.renderTBodyData[cellInfoParse.rowIndex][cellInfoParse.colIndex]
      }
      else {
        item = this.renderTHeadData[cellInfoParse.rowIndex][cellInfoParse.colIndex]
      }
      const cellData = {
        id: cell.dataset.selectFlag,
        size: item.size,
        color: item.isColorChange ? item.color : (cellInfoParse.tag === 'td' ? '#8691A0' : '#000000'),
        align: item.align,
        valign: item.valign,
        isWeight: item.isWeight,
        isItalic: item.isItalic,
        underline: item.underline,
        isColorChange: item.isColorChange,
        isShow: item.isShow,
        cellFill: item.cellFill,
        topBorderColor: item.topBorderColor,
        bottomBorderColor: item.bottomBorderColor,
        leftBorderColor: item.leftBorderColor,
        rightBorderColor: item.rightBorderColor,
        content: {
          dataSetCode: item['dataSetCode'],	 //
          dataSetName: item['dataSetName'], //
          key: item['key'],									 // 字段编码
          label: item['label'],							 // 字段名称
          resultType: item['resultType'],		 // 返回类型
          displayOrder: item['displayOrder']
        },
        changeKey: []
      }
      this.$emit('changeTableSeting', {
        type: 'cell',
        data: cellData
      })
    },
    // 输入框的键盘按下监听
    inputKeyDown(event) {
      // 阻止撤销和还原的快捷键 冒泡行为
      if (event.ctrlKey && event.keyCode === 90) {
        event.stopPropagation()
      } else if (event.ctrlKey && event.keyCode === 89) {
        event.stopPropagation()
      }
    },
    /**
     * 表格tab键按下时改变选中效果
     */
    getInFocus() {
      // 获取页面当前聚焦的元素
      const cell = document.activeElement
      // 选中单元格
      this.selectCells = [cell.__vue__.$refs.input.offsetParent.dataset.selectFlag]
    },
    endSelect(e) { // 结束框选
      if (!this.isEdit) {
        return
      }
      this.mouseDownCell = null
      setTimeout(() => {
        clearInterval(this.timer)
        this.timer = null
      }, 80)
    },
    mouseUp(event) {
      if (!this.isEdit) {
        return
      }
      // 阻止事件冒泡
      event.stopPropagation()
      this.endSelect()
      if (event.button === 2) {
      // 有点击目标则可打开菜单
        if (this.getCurrSingleCell()) {
          this.getMenu(event)
        }
      }
    },
    mouseMove(event) {
      if (!this.mouseDownCell) { // 没有在表格中 按下鼠标
        return
      }
      if (this.isEdit) {
        // 阻止事件冒泡
        event.stopPropagation()
      }
      // 获取当前 鼠标在表格中的位置
      this.mouseEventDom = event.toElement
      if (!this.timer) { // 已经开启定时器 无需重复开启 没开时才会开启
        // this.$refs[this.tableId + 'setTypeTip'].close()
        this.timer = setInterval(this.selectCelling, 60)
      }
    },
    selectCelling() {
      if (!this.mouseDownCell || !this.mouseDownCell.dataset) { // 鼠标已经松开或者 已经移出表格
        return
      }
      const cells = []
      // 获取起始、结束 cell信息
      const currCell = getCell(this.mouseEventDom)
      const info1 = this.cellInfoParse(this.mouseDownCell.dataset.selectFlag)
      const info2 = this.cellInfoParse(currCell.dataset.selectFlag)
      const startCol = Math.min(info1.colIndex, info2.colIndex)
      const endCol = Math.max(info1.colIndex, info2.colIndex)
      info1.rowIndex += (info1.tag === 'td' ? this.renderTHeadData.length : 0)
      info2.rowIndex += (info2.tag === 'td' ? this.renderTHeadData.length : 0)
      const startRow = Math.min(info1.rowIndex, info2.rowIndex)
      const endRow = Math.max(info1.rowIndex, info2.rowIndex)
      const data = this.renderTHeadData.concat(this.renderTBodyData)
      // 筛选选中cell
      for (let i = 0; i <= endRow; i++) {
        for (let j = 0; j <= endCol; j++) {
          if ((i >= startRow || (data[i][j].rowspan !== 1 && i + data[i][j].rowspan > startRow)) &&
          (j >= startCol ||	(data[i][j].colspan !== 1 && j + data[i][j].colspan > startCol)) &&
                        !data[i][j].isRemove) {
            cells.push(data[i][j].selectFlag)
          }
        }
      }
      this.selectCells = cells
      if (this.selectCells.length > 1) {
        this.execInputFunc(this.cellInfoParse(this.selectCells[0]), this.selectCells[0], 'Blur')
        this.execInputFunc(this.cellInfoParse(this.selectCells[this.selectCells.length - 1]), this.selectCells[this.selectCells.length - 1], 'Blur')
        // this.$refs[this.tableId + 'setTypeTip'].close()
      }
    },
    /**
     * 获取输入框值以及生成单元格唯一标识
     * @param tag th表头、td单元格
     * @param item 单元格数据
     * @param row 行索引
     * @param col 列索引
     */
    getVal(tag, item, row, col) {
      item.selectFlag = `${tag}-${row}-${col}-${item.rowspan || 1}-${item.colspan || 1}`
      return item.val
    },
    /**
     * return  是否可进行合并单元格操作
     */
    isAllowMerge() { //
    // 1.选中的单元格 数量小于两个 不可进行合并操作
      if (this.selectCells.length < 2) {
        return false
      }
      // 2.thead不能与 tbody 合并
      const tag = this.selectCells[0].split('-')[0]
      if (this.selectCells.some(item => item.split('-')[0] !== tag)) {
        return false
      }
      let arr = []
      this.selectCells.forEach(item => { // 将得到的数据 解析为二维数据
        const info = this.cellInfoParse(item)
        for (let i = info.rowIndex; i < info.rowIndex + info.rowNum; i++) {
          for (let j = info.colIndex; j < info.colIndex + info.colNum; j++) {
            if (!arr[i]) { 	arr[i] = [] }
            arr[i][j] = 1
          }
        }
      })
      arr = arr.filter(item => item)
      if (arr.some(item => item.length !== arr[0].length)) { // 横向是否平整
        return false
      }
      // /纵向是否平整
      let colArr = new Array(arr[0].length).fill(0)
      for (let i = 0; i < arr[0].length; i++) {
        for (let j = 0; j < arr.length; j++) {
          if (arr[j][i]) {
            colArr[i] += 1
          }
        }
      }
      colArr =	colArr.filter(item => item)
      return !colArr.some(item => item !== colArr[0])
    },

    isAllowSplit() { // 是否允许拆分单元格
      if (this.selectCells.length > 1) {
        return false
      }
      // 选中的单元格或者右击的单元格 rowspan或者colspan ！=1
      const info = this.cellInfoParse(this.getCurrSingleCell())
      return info.rowNum > 1 || info.colNum > 1
    },
    // 是否允许设置为单选
    isAllowSetOtherType() {
      if (this.selectCells.length === 0) {
        const info = this.cellInfoParse(this.rightDownCell.dataset.selectFlag)
        return !(info.tag === 'th' || info.rowNum !== 1 || info.colNum !== 1)
      }
      return !this.selectCells.some(item => {
        const info = this.cellInfoParse(item)
        return (info.tag === 'th' || info.rowIndex + '' !== this.selectCells[0].split('-')[1] ||
        info.rowNum !== 1 || info.colNum !== 1)
      })
    },
    // 获取待操作的单元格
    getActionFlags() {
      return this.selectCells.length === 0
        ? [this.rightDownCell.dataset.selectFlag] : this.selectCells
    },
    // 只能合并文本类型的单元
    isSelectAllThemText() { // 是否选中的都是文本
      return	!this.getActionFlags().some(item => {
        const info = this.cellInfoParse(item)
        const data = 	info.tag === 'th' ? this.renderTHeadData : this.renderTBodyData
        return data[info.rowIndex][info.colIndex].cellType !== 'text'
      })
    },
    // 是否允许设为结果列
    isAllowSetResultCell() {
      if (this.selectCells.length > 1) {
        return false
      }
      const info = 	this.cellInfoParse(this.getCurrSingleCell())
      return info.tag !== 'th'
    },
    /**
		 * 是否允许删除行
		 * @param {Object} event
		 */
    isAllowRemoveRow(event) {
      // const cell = getCell(event.toElement || event.explicitOriginalTarget)
      // 得到当前选中单元格的样式配置
      // const cellInfoParse = this.cellInfoParse(cell.dataset.selectFlag)

      // 选中数据都在一行 则可进行删除
      if (this.selectCells.length < 2) {
        return true
      }
      const fristInfo = this.cellInfoParse(this.selectCells[0])
      return 	!this.selectCells.some(item => {
        const info = this.cellInfoParse(item)
        return 	fristInfo.rowIndex !== info.rowIndex
      })
    },
    isAllowRemoveCol() { // 是否允许删除列
    // 选中数据都在一行 则可进行删除
      if (this.selectCells.length < 2) {
        return true
      }
      const fristInfo = this.cellInfoParse(this.selectCells[0])
      return 	!this.selectCells.some(item => {
        const info = this.cellInfoParse(item)
        return 	fristInfo.colIndex !== info.colIndex
      })
    },
    isSetEdit() { // 是否允许设置为可编辑或者不可编辑
      if (this.selectCells.length === 0) {
        const info = this.cellInfoParse(this.rightDownCell.dataset.selectFlag)
        if (info.tag === 'th') {
          return 	this.renderTHeadData[info.rowIndex][info.colIndex].cellType === 'text'
        }
        return 	this.renderTBodyData[info.rowIndex][info.colIndex].cellType === 'text'
      } else {
        for (let i = 0; i < this.selectCells.length; i++) {
          const info = this.cellInfoParse(this.rightDownCell.dataset.selectFlag)
          let celltype = ''
          if (info.tag === 'th') {
            celltype = 	this.renderTHeadData[info.rowIndex][info.colIndex].cellType
          } else {
            celltype = 	this.renderTBodyData[info.rowIndex][info.colIndex].cellType
          }
          if (celltype !== 'text') {
            return false
          }
        }
      }
      return true
    },
    getMenu(event) { // 获取菜单
      this.allowMerging = this.isAllowMerge()
      // 拆分单元格 选中的是一个 或者 没有选中 且右击了单元格 同时 rouspan、colspan ！=1
      //  &&this.isSelectAllThemText()
      const sallowEdit = this.isSetEdit()
      this.menuList = [
        { label: '合并单元格', code: 'merge', enable: this.selectCells.length > 1 && this.allowMerging }, // 0
        { label: '拆分单元格', code: 'split', enable: this.isAllowSplit() }, // 1
        { label: '设为结果列', code: 'resultCol', hide: this.tableModel === 0, enable: this.isAllowSetResultCell() }, // 2 tableModel
        { label: '插入整行', code: 'insertRow', enable: true }, // 3
        { label: '插入整列', code: 'insertCol', enable: true }, // 4
        { label: '删除整行', code: 'deleteRow', hide: false, enable: this.isAllowRemoveRow(event) },
        { label: '删除整列', code: 'deleteCol', hide: false, enable: this.isAllowRemoveCol() },
        { label: '设为可编辑单元', code: 'Editable', hide: true, enable: sallowEdit },
        { label: '设为不可编辑单元', code: 'noEditable', hide: true, enable: sallowEdit },
        { label: '文本对齐方式', code: 'alignment', hide: true }, // 9
        { label: '清空内容', code: 'clearContent', enable: true },
        { label: '清空样式', code: 'clearStyle', enable: true },
        { label: '保存映射', code: 'mapping', enable: this.selectCells.length === 2 }
      ] // 6
      this.$nextTick(() => {
        // 是否加入合并单元格功能
        this.$refs[this.tableId + 'menu'].open(event, (code, val) => {
          switch (code) {
            case 'merge' : this.mergingCell(); this.selectCells = []; break 		// 合并
            case 'split' : this.cellSpilt();	 this.selectCells = []; break 		// 拆分 取消单元格选中
            case 'resultCol' : this.setResultCell(); break 													// 设置结果列
            case 'insertRow' : this.insertRow(val);	this.selectCells = []; break 			// 插入行
            case 'insertCol' : this.insertCol(val); this.selectCells = []; break 			// 插入列
            case 'deleteRow' : this.removeRow(); this.selectCells = []; break
            case 'deleteCol' : this.removeCol();	this.selectCells = []; break
            case 'Editable' : this.setEditCell(); break
            case 'noEditable' : this.setNoEditCell(); break
            case 'alignment' : this.setTextAligin(val); break
            case 'clearContent' : this.clearContent('content'); break
            case 'clearStyle' : this.clearContent('style'); break
            case 'mapping' : this.saveMappingRelation(this.selectCells); this.selectCells = []; break
          }
        })
      })
    },
    /**
     * 保存映射关系
     */
    saveMappingRelation(selectCells) {
      this.saveMappingFunction(selectCells, this.renderTBodyData)
    },
    /**
		 * 清空内容
		 */
    clearContent(empty) {
      const bodyData = JSON.parse(JSON.stringify(this.renderTBodyData))
      /**
			 * 清空值和清空样式分两种:
			 * 	1.直接右键,清除当前右键选中单元格的值或者样式
			 *  2.多选后右键,清除当前多选的所有单元格的值或者样式
			 */
      // 清空值
      const resetItemContent = (item) => {
        item['val'] = ''
        item['dataSetCode'] = ''
        item['dataSetName'] = ''
        item['key'] = ''
        item['label'] = ''
        item['resultType'] = ''
        item['tag'] = ''
        item['displayOrder'] = null
        this.$forceUpdate()
      }
      // 清空样式
      const resetItemStyle = (item) => {
        item['isWeight'] = false
        item['isItalic'] = false
        item['underline'] = false
        item['cellFill'] = 'rgba(254, 254, 254, 1)'
        item['topBorderColor'] = null
        item['bottomBorderColor'] = null
        item['leftBorderColor'] = null
        item['rightBorderColor'] = null
        item['color'] = 'rgba(20, 0, 0, 1)'
        this.$forceUpdate()
      }
      // 选中单元数据
      const selectCellsData = []
      if (this.selectCells.length) {
        this.selectCells.forEach(item => {
          const info = this.cellInfoParse(item)
          const data = info.tag === 'th' ? this.renderTHeadData : this.renderTBodyData
          // 添加到数组中
          selectCellsData.push(JSON.parse(JSON.stringify(data[info.rowIndex][info.colIndex])))
          // 清空值
          if (empty === 'content')resetItemContent(data[info.rowIndex][info.colIndex])
          // 清空样式
          else if (empty === 'style')resetItemStyle(data[info.rowIndex][info.colIndex])
        })
      }
      else {
        const info = this.cellInfoParse(this.getCurrSingleCell())
        const data = info.tag === 'th' ? this.renderTHeadData : this.renderTBodyData
        // 添加到数组中
        selectCellsData.push(JSON.parse(JSON.stringify(data[info.rowIndex][info.colIndex])))
        // 清空值
        if (empty === 'content')resetItemContent(data[info.rowIndex][info.colIndex])
        // 清空样式
        else if (empty === 'style')resetItemStyle(data[info.rowIndex][info.colIndex])
      }
      // 触发清空内容方法
      this.$emit('clearContent', {
        renderTBodyData: bodyData,
        selectCellsData: selectCellsData
      })
    },
    setTextAligin(val) {
      if (this.selectCells.length === 0) {
        const info = this.cellInfoParse(this.rightDownCell.dataset.selectFlag)
        if (info.tag === 'th') {
          this.renderTHeadData[info.rowIndex][info.colIndex].textAlign = val
        } else {
          this.renderTBodyData[info.rowIndex][info.colIndex].textAlign = val
        }
      } else {
        this.selectCells.forEach(cell => {
          const info = this.cellInfoParse(cell)
          if (info.tag === 'th') {
            this.renderTHeadData[info.rowIndex][info.colIndex].textAlign = val
          } else {
            this.renderTBodyData[info.rowIndex][info.colIndex].textAlign = val
          }
        })
      }
      this.$forceUpdate()
    },
    // isEditCell
    setEditCell() {
      if (this.selectCells.length === 0) {
        const info = this.cellInfoParse(this.rightDownCell.dataset.selectFlag)
        if (info.tag === 'th') {
          this.renderTHeadData[info.rowIndex][info.colIndex].isEditCell = true
        } else {
          this.renderTBodyData[info.rowIndex][info.colIndex].isEditCell = true
        }
      } else {
        this.selectCells.forEach(cell => {
          const info = this.cellInfoParse(cell)
          if (info.tag === 'th') {
            this.renderTHeadData[info.rowIndex][info.colIndex].isEditCell = true
          } else {
            this.renderTBodyData[info.rowIndex][info.colIndex].isEditCell = true
          }
        })
      }
    },
    setNoEditCell() {
      if (this.selectCells.length === 0) {
        const info = this.cellInfoParse(this.rightDownCell.dataset.selectFlag)
        if (info.tag === 'th') {
          this.renderTHeadData[info.rowIndex][info.colIndex].isEditCell = false
        } else {
          this.renderTBodyData[info.rowIndex][info.colIndex].isEditCell = false
        }
      } else {
        this.selectCells.forEach(cell => {
          const info = this.cellInfoParse(cell)
          if (info.tag === 'th') {
            this.renderTHeadData[info.rowIndex][info.colIndex].isEditCell = false
          } else {
            this.renderTBodyData[info.rowIndex][info.colIndex].isEditCell = false
          }
        })
      }
    },
    /**
     * 删除单个表格行
     * @param dataArr 数据数组  表头数据 或者 表体数据
     * @param indexInfo 索引信息
     */
    removeSingleRow(dataArr, indexInfo) {
      const selectCellsData = []
      // 所有合并单元格的行索引
      const rowDataArray = this.getRowColIndexArray('row', indexInfo.tag)
      // 已计算rowspan的索引数组 防止重复计算
      const alreadyCount = []
      // 遍历当前选中这一行的所有单元格
      for (let j = 0; j < dataArr[indexInfo.rowIndex].length; j++) {
        // 当前单元格列索引
        const colIndex = j
        // 获取当前选中行 当前列 是否属于合并单元格
        const mergeCell = rowDataArray[indexInfo.rowIndex] ? rowDataArray[indexInfo.rowIndex][colIndex] : null
        // 不是合并单元格 或者纵向合并为1
        if (!mergeCell || mergeCell.rowspan === 1) {
          selectCellsData.push(dataArr[indexInfo.rowIndex][j])
          continue
        }
        const mergeRowIndex = mergeCell.rowIndex
        const mergeColIndex = mergeCell.colIndex
        // 当前是合并单元格，并且不是合并单元格的第一行（除了第一行，其余都要修改）
        if (mergeCell && indexInfo.rowIndex !== mergeCell.rowIndex) {
          if (!alreadyCount.includes(mergeRowIndex + ',' + mergeColIndex)) {
            // 添加已计算colspan的索引数组
            alreadyCount.push(mergeRowIndex + ',' + mergeColIndex)
            dataArr[mergeCell.rowIndex][mergeCell.colIndex].rowspan--
            selectCellsData.push(dataArr[indexInfo.rowIndex][j])
          }
        }
        // 当前是合并单元格，并且是合并单元格的第一行,并且不是同一列（是同一列表示选中的既是合并单元格，否则就不是）
        else if (mergeCell && indexInfo.rowIndex === mergeCell.rowIndex &&
          indexInfo.colIndex !== mergeCell.colIndex) {
          if (!alreadyCount.includes(mergeRowIndex + ',' + mergeColIndex)) {
            // 添加已计算colspan的索引数组
            alreadyCount.push(mergeRowIndex + ',' + mergeColIndex)
            dataArr[indexInfo.rowIndex + 1][j].colspan = dataArr[indexInfo.rowIndex][j].colspan
            dataArr[indexInfo.rowIndex + 1][j].rowspan = dataArr[indexInfo.rowIndex][j].rowspan - 1
            dataArr[indexInfo.rowIndex + 1][j].isRemove = false
            selectCellsData.push(dataArr[indexInfo.rowIndex][j])
          }
        }
      }
      dataArr.splice(indexInfo.rowIndex, 1)
      return selectCellsData
    },
    removeRow() { // 删除行
      const info = this.cellInfoParse(this.getCurrSingleCell())
      // 获取当前单元格的所有信息，
      const cellInfo = info.tag === 'td' ? this.renderTBodyData[info['rowIndex']][info['colIndex']] : this.renderTHeadData[info['rowIndex']][info['colIndex']]
      // 删除行数组
      const infoArray = []
      // 获取点击单元格的rowspan
      const cellRowspan = cellInfo.rowspan
      // 当前是合并单元格
      if (cellRowspan > 1) {
        // 根据合并单元格数 生成所覆盖的 行数组
        for (let i = cellRowspan; i > 0; i--) {
          // 复制单元格索引信息
          const copyInfo = JSON.parse(JSON.stringify(info))
          // 设置 行索引
          copyInfo.rowIndex = copyInfo.rowIndex + i - 1
          infoArray.push(copyInfo)
        }
      } else {
        // 不是合并单元格 直接取当前选中的
        infoArray.push(info)
      }
      // 删除的单元格数据
      let selectCellsData = []
      // 拷贝表头数据
      const copyTHeadData = this.renderTHeadData.slice(0)
      // 拷贝表体数据
      const copyTBodyData = this.renderTBodyData.slice(0)
      // 根据列数组删除单元格
      infoArray.forEach(item => {
        // 删除表头单元格列 并返回 删除的单元格数据
        const cellsData = this.removeSingleRow(info.tag === 'td' ? copyTBodyData : copyTHeadData, item)
        // 合并删除的单元格数据
        selectCellsData = selectCellsData.concat(cellsData)
      })
      this.renderTHeadData = []
      this.renderTBodyData = []
      this.$nextTick(() => {
        this.renderTHeadData = copyTHeadData
        this.renderTBodyData = copyTBodyData
        this.rowCelChange()
      })
      // 触发清空内容方法
      this.$emit('clearContent', {
        renderTBodyData: copyTBodyData,
        selectCellsData: selectCellsData
      })
    },
    removeCol() { // 删除列
      // 当前点击单元格
      const info = this.cellInfoParse(this.getCurrSingleCell())
      // 获取当前单元格的所有信息，
      const cellInfo = info.tag === 'td' ? this.renderTBodyData[info['rowIndex']][info['colIndex']] : this.renderTHeadData[info['rowIndex']][info['colIndex']]
      // 删除列数组
      const infoArray = []
      // 获取点击单元格的colspan
      const cellColspan = cellInfo.colspan
      // 当前是合并单元格
      if (cellColspan > 1) {
        // 根据合并单元格数 生成所覆盖的 列数组
        for (let i = cellColspan; i > 0; i--) {
          // 复制单元格索引信息
          const copyInfo = JSON.parse(JSON.stringify(info))
          // 设置 列索引
          copyInfo.colIndex = copyInfo.colIndex + i - 1
          infoArray.push(copyInfo)
        }
      } else {
        // 不是合并单元格 直接取当前选中的
        infoArray.push(info)
      }
      // 删除的单元格数据
      let selectCellsData = []
      // 拷贝表头数据
      const copyTHeadData = this.renderTHeadData.slice(0)
      // 拷贝表体数据
      const copyTBodyData = this.renderTBodyData.slice(0)
      // 根据列数组删除单元格
      infoArray.forEach(item => {
        // 删除表头单元格列 并返回 删除的单元格数据
        const headCellsData = this.removeSingleCol(copyTHeadData, item)
        // 删除表体单元格列 并返回 删除的单元格数据
        const bodyCellsData = this.removeSingleCol(copyTBodyData, item)
        // 合并删除的单元格数据
        selectCellsData = selectCellsData.concat(headCellsData, bodyCellsData)
      })
      this.renderTHeadData = []
      this.renderTBodyData = []
      this.$nextTick(() => {
        this.renderTHeadData = copyTHeadData
        this.renderTBodyData = copyTBodyData
        this.rowCelChange()
      })
      // 触发清空内容方法
      this.$emit('clearContent', {
        renderTBodyData: copyTBodyData,
        selectCellsData: selectCellsData
      })
    },
    /**
     * 删除单个表格列
     * @param dataArr 数据数组  表头数据 或者 表体数据
     * @param indexInfo 索引信息
     */
    removeSingleCol(dataArr, indexInfo) {
      // 删除单元格数据
      const selectCellsData = []
      for (let i = 0; i < dataArr.length; i++) {
        // 已删除标识
        let alreadyDelete = false
        for (let j = indexInfo.colIndex; j >= 0; j--) {
          if (!dataArr[i][j]) {
            return
          }
          // 当有合并行 且不是删除起始行  合并单元格最左上单元格 colspan -1
          if (dataArr[i][j].colspan + j > indexInfo.colIndex && j < indexInfo.colIndex) {
            dataArr[i][j].colspan--
          }
          // 当前删除的是 本行最后一列时  直接删除
          if (indexInfo.colIndex + 1 === dataArr[i].length && !alreadyDelete) {
            selectCellsData.push(dataArr[i][j])
            dataArr[i].splice(j, 1)
            alreadyDelete = true
            // 否则判断是否是需要进行操作的列
          } else if (indexInfo.colIndex === j && !alreadyDelete) {
            // 如果删除的是合并首列 则需要进行属性继承
            if (dataArr[i][j].colspan > 1 && !dataArr[i][j].isRemove) {
              dataArr[i][j + 1].colspan = dataArr[i][j].colspan - 1
              dataArr[i][j + 1].isRemove = false
              dataArr[i][j + 1].rowspan = dataArr[i][j].rowspan
            }
            selectCellsData.push(dataArr[i][j])
            dataArr[i].splice(j, 1)
            alreadyDelete = true
          }
        }
      }
      return selectCellsData
    },
    setResultCell() { // 设置结果列
      // this.$refs[this.tableId + 'setTypeTip'].close()
      // 只允许有一个结果列
      for (let i = 0; i < this.renderTBodyData.length; i++) {
        for (let j = 0; j < this.renderTBodyData[i].length; j++) {
          if (this.renderTBodyData[i][j].cellType === 'result') {
            this.renderTBodyData[i][j].cellType = 'text'
          }
        }
      }
      const info = this.cellInfoParse(this.getCurrSingleCell())
      const cell = this.renderTBodyData[info.rowIndex][info.colIndex]
      cell.cellType = 'result'
      cell.val = ''
      cell.label = ''
    },
    cellInfoParse(currSelect) { // 单元格信息解析
      const info = currSelect.split('-')
      const tag = info[0]
      const rowIndex = parseInt(info[1])
      const colIndex = parseInt(info[2])
      const rowNum = parseInt(info[3])
      const colNum = parseInt(info[4])
      return { tag, rowIndex, colIndex, rowNum, colNum }
    },
    // 获取当前需要操作的单个单元格 selectFlag
    getCurrSingleCell() {
      return this.selectCells.length
        ? this.selectCells[0] : (this.rightDownCell.dataset || {}).selectFlag
    },
    /**
     * 设置插入时的单元格默认值
     */
    settingDefaultCell(cell) {
      cell.cellFill = this.options.cellFill
      return cell
    },
    /**
		 * 插入列
		 */
    insertCol(direction) {
      // 获取所选单元格索引信息
      const info = this.cellInfoParse(this.getCurrSingleCell())
      const itemArr = [this.renderTHeadData,	this.renderTBodyData]
      itemArr.forEach((arr, index) => { // 表头 /表体
        if (!arr.length) {
          return
        }
        // 获取全部单元格列索引数组
        const colIndexArray = this.getRowColIndexArray('col', index === 0 ? 'th' : 'td')
        // 已计算colspan的索引数组 防止重复计算
        const alreadyCount = []
        arr.forEach((item, rowIndex) => { // 行
          // 给出默认值
          const cell = this.settingDefaultCell(JSON.parse(JSON.stringify(generalTableConstant.DEFAULT_CELL)))
          // 设置单元格默认显示
          cell.isRemove = false
          cell.isShow = true
          // 所选单元格colspan
          const selectColspan = info.colNum
          // 所选单元格的最后列下标(如果所选单元格为合并单元格,则取合并单元格最后一个的下标)
          const selectLastIndex = selectColspan > 1 ? info.colIndex + selectColspan - 1 : info.colIndex
          // 所选单元格的第一个列下标
          const selectFirstIndex = info.colIndex
          // 插入列索引 向左取第一个列下标 向右取最后一个列下标+1
          const insertColIndex = direction === 'left' ? selectFirstIndex : selectLastIndex + 1
          // 获取当前选中列 当前行 是否属于合并单元格
          const mergeCell = colIndexArray[direction === 'left' ? selectFirstIndex : selectLastIndex] ? colIndexArray[direction === 'left' ? selectFirstIndex : selectLastIndex][rowIndex] : null
          // 不是合并单元格 或者纵向合并为1
          if (!mergeCell || mergeCell.colspan === 1) {
            // 插入单元格
            item.splice(insertColIndex, 0, cell)
            return
          }
          // 合并单元格的行索引
          const mergeRowIndex = mergeCell.rowIndex
          // 合并单元格的列索引
          const mergeColIndex = mergeCell.colIndex
          // 合并单元格的列合并数
          const mergeColspan = mergeCell.colspan
          // 最左侧索引是否匹配
          const leftIndexMatching = selectFirstIndex === mergeColIndex
          // 最右侧索引是否匹配
          const rightIndexMatching = selectLastIndex === mergeColIndex + mergeColspan - 1
          if (
            (!leftIndexMatching && !rightIndexMatching) || // 如果两侧都不匹配 说明选中单元格包含在 合并单元格列中 无论向左向右 均需要修改colspan
                  (leftIndexMatching && !rightIndexMatching && direction === 'right') || // 左侧匹配 右侧不匹配 且是向右添加 需要修改colspan
                  (!leftIndexMatching && rightIndexMatching && direction === 'left') // 左侧不匹配 右侧匹配 且是向左添加 需要修改colspan
          ) {
            if (!alreadyCount.includes(mergeRowIndex + ',' + mergeColIndex)) {
              // 将所属的合并单元格colspan+1
              arr[mergeRowIndex][mergeColIndex].colspan += 1
              // 添加已计算colspan的索引数组
              alreadyCount.push(mergeRowIndex + ',' + mergeColIndex)
            }
            // 将添加的单元格设置隐藏
            cell.isRemove = true
          }
          // 插入单元格
          item.splice(insertColIndex, 0, cell)
        })
      })
      this.rowCelChange()
    },
    // 获取行列索引数组
    getRowColIndexArray(type = 'col', tag = 'td') {
      let itemArr = []
      itemArr = tag === 'td' ? this.renderTBodyData : this.renderTHeadData
      // 行列索引数组
      const rowColIndexArray = new Array(type === 'col' ? itemArr[0].length : itemArr.length)
      // 降维数组
      const colDataArray = flatten(itemArr)
      // 获取合并单元格数组
      const mergeArr = colDataArray.filter(item => (item.colspan > 1 || item.rowspan > 1) && !item.isRemove)
      mergeArr.forEach(item => {
        const colspan = Number(item.colspan) // 合并列
        const rowspan = Number(item.rowspan) // 合并行
        const selectFlag = item.selectFlag // 索引标识
        const tempArr = selectFlag.split('-')
        const rowIndex = Number(tempArr[1]) // 行索引
        const colIndex = Number(tempArr[2]) // 列索引
        // 索引对象
        const indexObj = {
          rowIndex: rowIndex,
          colIndex: colIndex,
          rowspan: rowspan,
          colspan: colspan
        }
        if (type === 'col') {
          // 遍历colspan
          for (let i = 0; i < colspan; i++) {
            // 获取 列索引数组
            const colArray = rowColIndexArray[colIndex + i] || []
            // 遍历rowspan
            for (let j = 0; j < rowspan; j++) {
              // 添加索引对象到数组中
              colArray[rowIndex + j] = indexObj
            }
            rowColIndexArray[colIndex + i] = colArray
          }
        } else if (type === 'row') {
          // 遍历rowspan
          for (let i = 0; i < rowspan; i++) {
            // 获取 行索引数组
            const rowArray = rowColIndexArray[rowIndex + i] || []
            // 遍历colspan
            for (let j = 0; j < colspan; j++) {
              // 添加索引对象到数组中
              rowArray[colIndex + j] = indexObj
            }
            rowColIndexArray[rowIndex + i] = rowArray
          }
        }
      })
      return rowColIndexArray
    },
    /**
		 * 插入行
		 */
    insertRow(direction) {
      // 固定的表头&&向下插入行=向下插入一行表体
      // getCurrSingleCell获取当前需要操作的单个单元格
      const info = this.cellInfoParse(this.getCurrSingleCell())
      // 表格整体数据
      const renderData = this.getOperateData(info.tag)
      const copyRow = JSON.parse(JSON.stringify(renderData[info.rowIndex])).map(item => {
        const cell = this.settingDefaultCell(JSON.parse(JSON.stringify(generalTableConstant.DEFAULT_CELL)))
        // 保留部分属性
        cell['isShow'] = true
        cell.isRemove = false
        return cell
      })
      // 所有合并单元格的行列索引
      const rowDataArray = this.getRowColIndexArray('row', info.tag)
      // 当前选中的那行单元格
      const colNumber = renderData[info['rowIndex']]
      // 已计算rowspan的索引数组 防止重复计算
      const alreadyCount = []
      // 所选单元格rowspan
      const selectRowspan = info.rowNum
      // 所选单元格的最后行下标(如果所选单元格为合并单元格,则取合并单元格最后一个的下标)
      const selectLastIndex = selectRowspan > 1 ? info.rowIndex + selectRowspan - 1 : info.rowIndex
      // 所选单元格的第一个行下标
      const selectFirstIndex = info.rowIndex
      // 插入行索引 向上取第一个行下标 向下取最后一个行下标+1
      const insertRowIndex = direction === 'up' ? selectFirstIndex : selectLastIndex + 1
      for (let i = 0; i < colNumber.length; i++) {
        // 当前单元格列索引
        const colIndex = i
        // 获取当前选中行 当前列 是否属于合并单元格
        const mergeCell = rowDataArray[direction === 'up' ? selectFirstIndex : selectLastIndex] ? rowDataArray[direction === 'up' ? selectFirstIndex : selectLastIndex][colIndex] : null

        // 不是合并单元格 或者纵向合并为1
        if (!mergeCell || mergeCell.rowspan === 1) {
          continue
        }
        // 合并单元格的行索引
        const mergeRowIndex = mergeCell.rowIndex
        // 合并单元格的列索引
        const mergeColIndex = mergeCell.colIndex
        // 合并单元格的列合并数
        const mergeRowspan = mergeCell.rowspan
        // 最上方索引是否匹配
        const upIndexMatching = selectFirstIndex === mergeRowIndex
        // 最下方索引是否匹配
        const dowmIndexMatching = selectLastIndex === mergeRowIndex + mergeRowspan - 1
        if (
          (!upIndexMatching && !dowmIndexMatching) || // 如果上下都不匹配 说明选中单元格包含在 合并单元格行中 无论向上向下 均需要修改rowspan
                (upIndexMatching && !dowmIndexMatching && direction === 'down') || // 上方匹配 下方不匹配 且是向下添加 需要修改rowspan
                (!upIndexMatching && dowmIndexMatching && direction === 'up') // 上方不匹配 下方匹配 且是上方添加 需要修改rowspan
        ) {
          if (!alreadyCount.includes(mergeRowIndex + ',' + mergeColIndex)) {
            // 将所属的合并单元格colspan+1
            renderData[mergeRowIndex][mergeColIndex].rowspan += 1
            // 添加已计算colspan的索引数组
            alreadyCount.push(mergeRowIndex + ',' + mergeColIndex)
          }
          // 将添加的单元格设置隐藏
          copyRow[i].isRemove = true
        }
      }
      // 如果是在固定的表头进行向下插入则插入一行表体
      renderData.splice(insertRowIndex, 0, copyRow)
      this.rowCelChange()
    },
    getOperateData(tag) {
      return tag === 'th' ? this.renderTHeadData : this.renderTBodyData
    },
    // 单元格拆分
    cellSpilt() {
      const info = this.cellInfoParse(this.getCurrSingleCell())
      // 得到要进行操作的数据
      const data = this.getOperateData(info.tag)
      for (let i = info.rowIndex; i < info.rowIndex + info.rowNum; i++) {
        for (let j = info.colIndex; j < info.colIndex + info.colNum; j++) {
          data[i][j].rowspan = 1
          data[i][j].colspan = 1
          data[i][j].isRemove = false
          data[i][j].isEditCell = false
        }
      }
      this.rowCelChange()
    },
    /**
     * 合并单元格
     */
    mergingCell() { // 单元格合并
    // 标签名-行-列-rowspan-colspan
      const info = this.selectCells[0].split('-')
      const selectData = []
      // 需要操作多少行
      this.selectCells.forEach((cell, index) => {
        const row = parseInt(cell.split('-')[1])
        const col = parseInt(cell.split('-')[2])
        if (!selectData[row]) {
          selectData[row] = []
        }
        selectData[row][col] = {
          rowspan: parseInt(cell.split('-')[3]),
          colspan: parseInt(cell.split('-')[4])
        }
      })
      // 选择进行操作的数据
      const data = this.getOperateData(info[0])
      // 设置rowspan 与colspan
      const startRow = selectData.findIndex(item => item)
      let currRowspan = 0
      for (let i = startRow; i < selectData.length;) {
        if (selectData[i] && selectData[i][parseInt(info[2])]) {
          currRowspan += selectData[i][parseInt(info[2])].rowspan
          i += selectData[i][parseInt(info[2])].rowspan
        } else {
          currRowspan += 1
          i++
        }
      }
      data[parseInt(info[1])][parseInt(info[2])].rowspan = currRowspan
      const colspanArr = selectData[parseInt(info[1])].map(item => item.colspan).filter(item => item)
      const currColspan = colspanArr.length > 1 ? sum(colspanArr) : colspanArr[0]
      data[parseInt(info[1])][parseInt(info[2])].colspan = currColspan
      data[parseInt(info[1])][parseInt(info[2])].cellType = 'text' // 合并后 设为文本
      let isFrist = true
      selectData.forEach((item, index) => {
        if (item) { // 因为是直接用下标插入的 所以会有empty存在
        // 获取删除起始下标 与删除个数
          let startIndex = item.findIndex(d => d)
          let removeLength = 0
          for (let i = startIndex; i < item.length; i++) {
            removeLength += item[i] ? item[i].colspan : 0
          }
          if (isFrist) { // 第一个数据应该进行保留
            startIndex++
            removeLength--
            isFrist = false
            if (removeLength === 0) {
              return
            }
          }
          for (let i = startIndex; i < startIndex + removeLength; i++) {
            data[index][i].isRemove = true
            // data[index][i].val = ''
          }
        }
      })
      this.rowCelChange()
    },
    // --------------------常规事件方法
    changeRadio(row, col) {
      if (row !== undefined && col !== undefined) {
        this.renderTBodyData[row].forEach((item, index) => {
          item.otherSelect = (col === index ? true : null)
        })
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.select{
  background:#FAF0DE !important;
  span{
    color: #050F21 !important;
  }
  div{
    color:#050F21 !important;
  }
}
.isedit{
  background-color:#f2faf3 !important;
}
.dynamic-table2-wapper{
  // padding:20px;
  // min-height: 200px;
  // border-radius: 5px;
  overflow: hidden;
  // border:1px solid #dfe6ec;
  table-layout:fixed;
  .isPreview{
    user-select: auto !important;
  }
  .noPreview{
    user-select: none !important;
  }
  .dynamic-table2{
    width:100%;
    border-collapse: collapse;
    &:first-child tr{
      th{
        border-top:none !important;
      }
    }
    tr{
      &:first-child th{
        border-top:none !important;
        border-left:none !important;
      }
      th:first-child,td:first-child{
        border-left:none !important;
      }
      th:last-child,td:last-child{
        border-right:none !important;
      }
      &:last-child td{
        border-bottom:none !important;
      }
    }
    th{
      // background-color: #F9FAFB;
      font-weight: 300;
    }
    td{
      font-size:14px;
      color:#222222;
      // background-color: #ffffff;
    }
    td,th{
      word-wrap:break-word;
      border-spacing: 0;
      // border:1px solid #dfe6ec;
      box-sizing:border-box;
      padding:5px;
      overflow-x: auto;
    }
  }
}
.brder-right-none{
    border-right:none !important;
}
.brder-bottom-none{
    border-bottom:none !important;
}
.table-title{
  text-align:center;
  padding:10px 0;
  font-size:16px;
  font-weight:600;
}
</style>
